// Copyright (C) 1953-2022 NUDT
// Verilog module name - ptp_tx
// Version: V4.1.0.20221206
// Created:
//         by - fenglin 
////////////////////////////////////////////////////////////////////////////
// Description:
//         ptp transmit.
///////////////////////////////////////////////////////////////////////////
`timescale 1ns/1ps

module ptp_tx #(parameter osm_id = 8'h0)
(
        i_clk,
        i_rst_n,
		
		i_tsn_or_tte,		
              
        iv_data,
        i_data_wr,
       
        iv_local_cnt_rx,
        iv_eth_type,
		iv_tsmp_type,
		iv_tsmp_subtype,
		
        iv_local_cnt, 
            
        ov_data,
        o_data_wr,

        o_osm_req_tx_pulse,
        o_osm_resp_tx_pulse		
);

// I/O
// clk & rst
input                  i_clk;                   //125Mhz
input                  i_rst_n;

input                  i_tsn_or_tte;

input      [8:0]       iv_data;
input                  i_data_wr;

input      [23:0]      iv_local_cnt_rx;
input      [15:0]      iv_eth_type; 
input      [7:0]       iv_tsmp_type;
input      [7:0]       iv_tsmp_subtype;

input      [23:0]      iv_local_cnt;
// send pkt    
output reg [8:0]       ov_data;
output reg             o_data_wr;

output reg             o_osm_req_tx_pulse ;
output reg             o_osm_resp_tx_pulse;
//***************************************************
//   add valid of data and delay 8 cycles
//***************************************************
reg       [71:0]       rv_data;
reg       [10:0]       rv_byte_cnt;
always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin
        rv_data                       <= 72'h0;
		rv_byte_cnt                   <= 11'h0;
    end
    else begin
        if(i_data_wr == 1'b1)begin//write a pkt data to register
            rv_byte_cnt <= rv_byte_cnt + 1'b1;
            rv_data     <= {rv_data[62:0],iv_data};      
        end
        else begin
            rv_byte_cnt <= 11'b0;
            rv_data     <= {rv_data[62:0],9'b0};
        end
    end
end
//***************************************************
//        opensync correctionfield update
//***************************************************  
reg        [63:0]       rv_correctionfield_clock;
reg        [2:0]        rv_cf_update_state;  
     
localparam              IDLE_S                      = 3'd0,
                        UPDATE_PTP_CF_S             = 3'd1,
                        UPDATE_PCF_CF_S             = 3'd2,
						MODIFY_SOURCEPORTIDENTITY_S = 3'd3,
                        TRANS_PKT_S                 = 3'd4;   
always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin
        o_data_wr                   <= 1'b0;
        ov_data                     <= 9'h0;   
        rv_correctionfield_clock    <= 64'h0;
		
		o_osm_req_tx_pulse          <= 1'b0 ;
		o_osm_resp_tx_pulse         <= 1'b0 ;
        rv_cf_update_state          <= IDLE_S;
    end
    else begin
        case(rv_cf_update_state)
            IDLE_S: begin
				rv_correctionfield_clock    <= 64'h0;
				o_osm_req_tx_pulse          <= 1'b0 ;
				o_osm_resp_tx_pulse         <= 1'b0 ;				
				if(rv_data[71])begin
					o_data_wr    <= 1'b1;
					ov_data      <= rv_data[71:63];
                    if((iv_eth_type == 16'hff01) && (iv_tsmp_type == 8'h06))begin//opensync.
						if((iv_tsmp_subtype == 8'h01) || (iv_tsmp_subtype == 8'h02) || (iv_tsmp_subtype == 8'h03) || (iv_tsmp_subtype == 8'h07) || (iv_tsmp_subtype == 8'h08) || (iv_tsmp_subtype == 8'h09))begin//Sync、Pdelay_req、Pdelay_resp、follow_up、signaling和announce封装报文
							if(i_tsn_or_tte)begin//tsn
								rv_cf_update_state <= UPDATE_PTP_CF_S;
							end
							else begin//tte
								rv_cf_update_state <= UPDATE_PCF_CF_S;
							end
					    end
						else begin 						
							rv_cf_update_state          <= TRANS_PKT_S;
					    end
                    end
                    else begin
                        rv_cf_update_state <= TRANS_PKT_S;
                    end
			    end
				else begin
					o_data_wr          <= 1'b0;
				    ov_data            <= 9'h0;
					rv_cf_update_state <= IDLE_S;
				end
			end              
            UPDATE_PTP_CF_S:begin//updata calculates clock of ptp 
                o_data_wr    <= 1'b1;
				if(rv_byte_cnt < 11'd30)begin
				    ov_data  <= rv_data[71:63];
                    if(rv_byte_cnt == 11'd29)begin
					    if(iv_tsmp_subtype == 8'h01)begin//sync
							rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};
							o_osm_req_tx_pulse          <= 1'b0 ;
						    o_osm_resp_tx_pulse         <= 1'b0 ;
                            if(iv_local_cnt > iv_local_cnt_rx)begin//本地计数器未计满
                                rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt - iv_local_cnt_rx);
                            end
                            else begin//本地计数器计满
                                rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt + 24'hffffff - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt - iv_local_cnt_rx);
                            end                            
						end
						else begin
						    rv_correctionfield_clock <= rv_correctionfield_clock;
							if(iv_tsmp_subtype == 8'h02)begin//pdelay_req
								o_osm_req_tx_pulse          <= 1'b1 ;
								o_osm_resp_tx_pulse         <= 1'b0 ;							
							end
							else if(iv_tsmp_subtype == 8'h03)begin//pdelay_resp
								o_osm_req_tx_pulse          <= 1'b0 ;
								o_osm_resp_tx_pulse         <= 1'b1 ;								
							end
							else begin
								o_osm_req_tx_pulse          <= 1'b0 ;
								o_osm_resp_tx_pulse         <= 1'b0 ;								
							end
						end
                        //if(iv_local_cnt > iv_local_cnt_rx)begin
                        //    rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt - iv_local_cnt_rx);
                        //    rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};
                        //end
                        //else begin
                        //    rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt + 65'h1_0000_0000_0000_0000 - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt + 65'h1_0000_0000_0000_0000 - iv_local_cnt_rx);
                        //    rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};
                        //end                        
                    end
                    else begin
                        o_osm_req_tx_pulse          <= 1'b0 ;
						o_osm_resp_tx_pulse         <= 1'b0 ;	
						rv_correctionfield_clock <= rv_correctionfield_clock;
                    end                    
				end
				else if(rv_byte_cnt <= 11'd37)begin
					o_osm_req_tx_pulse          <= 1'b0 ;
					o_osm_resp_tx_pulse         <= 1'b0 ;					
                    case(rv_byte_cnt)                           
                        11'd30:ov_data    <= {1'b0,rv_correctionfield_clock  [63:56]};
                        11'd31:ov_data    <= {1'b0,rv_correctionfield_clock  [55:48]};
                        11'd32:ov_data    <= {1'b0,rv_correctionfield_clock  [47:40]};
                        11'd33:ov_data    <= {1'b0,rv_correctionfield_clock  [39:32]};
                        11'd34:ov_data    <= {1'b0,rv_correctionfield_clock  [31:24]};
                        11'd35:ov_data    <= {1'b0,rv_correctionfield_clock  [23:16]};
                        11'd36:ov_data    <= {1'b0,rv_correctionfield_clock  [15:8] };
                        11'd37:ov_data    <= {1'b0,rv_correctionfield_clock  [7:0]  };
                        default:ov_data   <= rv_data[71:63];					
                    endcase
			    end
                else begin
					o_osm_req_tx_pulse          <= 1'b0 ;
					o_osm_resp_tx_pulse         <= 1'b0 ;	
					
                    ov_data                     <= rv_data[71:63];
                    rv_cf_update_state          <= MODIFY_SOURCEPORTIDENTITY_S;
                end
            end
			MODIFY_SOURCEPORTIDENTITY_S:begin//modify sync port of SOURCEPORTIDENTITY
				o_osm_req_tx_pulse          <= 1'b0 ;
				o_osm_resp_tx_pulse         <= 1'b0 ;
				
				o_data_wr                   <= 1'b1;
				if(rv_byte_cnt <= 11'd41)begin
					ov_data                     <= rv_data[71:63];  
				end
				else if(rv_byte_cnt <= 11'd51)begin//sourceportidentity
                    if(rv_byte_cnt <= 11'd49)begin
						ov_data                     <= rv_data[71:63];  
                    end
                    else if(rv_byte_cnt == 11'd50)begin//port 
						if((iv_tsmp_subtype == 8'h01) || (iv_tsmp_subtype == 8'h07) || (iv_tsmp_subtype == 8'h08) || (iv_tsmp_subtype == 8'h09))begin//sync、follow_up、signaling和announce封装报文
						    ov_data                     <= 9'h0;  
						end
						else begin
						    ov_data                     <= rv_data[71:63];
						end
                    end
                    else if(rv_byte_cnt == 11'd51)begin//port 
						if((iv_tsmp_subtype == 8'h01) || (iv_tsmp_subtype == 8'h07) || (iv_tsmp_subtype == 8'h08) || (iv_tsmp_subtype == 8'h09))begin//sync、follow_up、signaling和announce封装报文
						    ov_data                     <= {1'b0,osm_id}; 
						end
						else begin
						    ov_data                     <= rv_data[71:63];
						end						
                    end					
                    else begin
						ov_data                     <= rv_data[71:63]; 
                    end					
				end
                else begin
					ov_data                     <= rv_data[71:63]; 
				    rv_cf_update_state          <= TRANS_PKT_S;						
                end 						
			
			end
            UPDATE_PCF_CF_S:begin//updata calculates clock of ptp 
                o_data_wr    <= 1'b1;
				if(rv_byte_cnt < 11'd42)begin
				    ov_data  <= rv_data[71:63];
                    if(rv_byte_cnt == 11'd41)begin
                        rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};                    
                        if(iv_local_cnt > iv_local_cnt_rx)begin//本地计数器未计满    
                            rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt - iv_local_cnt_rx);
                            //if(iv_local_cnt > iv_local_cnt_rx)begin
                            //    rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt - iv_local_cnt_rx);
                            //    rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};
                            //end
                            //else begin
                            //    rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt + 65'h1_0000_0000_0000_0000 - iv_local_cnt_rx);//{rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9],rv_data[7:0],iv_data[7:0]} + (iv_local_cnt + 65'h1_0000_0000_0000_0000 - iv_local_cnt_rx);
                            //    rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};
                            //end
                        end
                        else begin//本地计数器计满 
                            rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + (iv_local_cnt + 24'hffffff - iv_local_cnt_rx);
                        end                        
                    end
                    else begin
                        rv_correctionfield_clock <= rv_correctionfield_clock;
                    end                    
				end
				else if(rv_byte_cnt <= 11'd49)begin
                    case(rv_byte_cnt)                           
                        11'd42:ov_data    <= {1'b0,rv_correctionfield_clock  [63:56]};
                        11'd43:ov_data    <= {1'b0,rv_correctionfield_clock  [55:48]};
                        11'd44:ov_data    <= {1'b0,rv_correctionfield_clock  [47:40]};
                        11'd45:ov_data    <= {1'b0,rv_correctionfield_clock  [39:32]};
                        11'd46:ov_data    <= {1'b0,rv_correctionfield_clock  [31:24]};
                        11'd47:ov_data    <= {1'b0,rv_correctionfield_clock  [23:16]};
                        11'd48:ov_data    <= {1'b0,rv_correctionfield_clock  [15:8] };
                        11'd49:ov_data    <= {1'b0,rv_correctionfield_clock  [7:0]  };
                        default:ov_data   <= rv_data[71:63];					
                    endcase
			    end
                else begin
                    ov_data            <= rv_data[71:63];
                    rv_cf_update_state <= TRANS_PKT_S;
                end
            end            
			TRANS_PKT_S:begin
			    o_osm_req_tx_pulse          <= 1'b0 ;
			    o_osm_resp_tx_pulse         <= 1'b0 ;
                ov_data                     <= rv_data[71:63];
                o_data_wr                   <= 1'b1;                
				if(rv_data[71] == 1'b1)begin
                    rv_cf_update_state <= IDLE_S;
				end
				else begin
				    rv_cf_update_state <= TRANS_PKT_S;
				end
			end
            default:begin
				o_data_wr                     <= 1'b0;
				ov_data                       <= 9'h0;
			    o_osm_req_tx_pulse            <= 1'b0 ;
			    o_osm_resp_tx_pulse           <= 1'b0 ;					
				rv_correctionfield_clock      <= 64'h0;
                rv_cf_update_state            <= IDLE_S;
            end
        endcase
    end
end
endmodule 